﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using ProjectEuler.Sudoku;

namespace ProjectEuler.Problems
{
    [EulerProblem(96, 24702)]
    [Description("Devise an algorithm for solving Su Doku puzzles.")]
    internal sealed class Problem096 : EulerProblem
    {
        public override Object Solve()
        {
            using (var reader = OpenTextAttachment())
            {
                return (from p in ReadSudoku(reader)
                        select GetUpperLeftNumber(p)).Sum();
            }
        }

        private static Int32 GetUpperLeftNumber(SudokuPuzzle puzzle)
        {
            return (100 * puzzle[0, 0].Value) + (10 * puzzle[0, 1].Value) + (puzzle[0, 2].Value);
        }

        private static IEnumerable<SudokuPuzzle> ReadSudoku(TextReader reader)
        {
            var buffer = new Int32[9, 9];
            var name = String.Empty;

            while ((name = reader.ReadLine()) != null)
            {
                for (int y = 0; y < 9; y++)
                {
                    var digits = reader.ReadLine().ToCharArray();

                    for (int x = 0; x < 9; x++)
                    {
                        buffer[y, x] = digits[x] - '0';
                    }
                }

                var puzzle = new SudokuPuzzle(buffer);
                var solver = new SudokuBacktrackingSolver(puzzle);

                if (!solver.TryFindSolution())
                {
                    throw new Exception("Failed to solve " + name);
                }

                yield return puzzle;
            }
        }
    }
}
